home *** CD-ROM | disk | FTP | other *** search
- /* net/rom level 4 (transport) protocol user level calls
- * Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
- * non-commercial distribution only.
- */
-
- #include "global.h"
- #ifdef NETROM
- #include "mbuf.h"
- #include "timer.h"
- #include "ax25.h"
- #include "netrom.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: nr4user.c,v 1.9 1996/09/04 01:34:13 root Exp root $";
- #endif
-
- #undef NR4DEBUG
-
-
- /* Open a NET/ROM transport connection */
- struct nr4cb *
- open_nr4 (local, remote, mode, r_upcall, t_upcall, s_upcall, user)
- struct nr4_addr *local; /* local node address */
- struct nr4_addr *remote; /* destination node address */
- int mode; /* active/passive/server */
- void (*r_upcall) (struct nr4cb *, int16); /* received data upcall */
- void (*t_upcall) (struct nr4cb *, int16); /* transmit upcall */
- void (*s_upcall) (struct nr4cb *, int, int); /* state change upcall */
- int user; /* user linkage area */
- {
- struct nr4cb *cb;
- struct nr4hdr hdr;
- struct nr4_addr nr4tmp;
-
- if ((cb = new_n4circ ()) == NULLNR4CB)
- return NULLNR4CB; /* No circuits available */
-
- if (remote == NULLNRADDR) {
- remote = &nr4tmp;
- (void) setcall (remote->user, " ");
- (void) setcall (remote->node, " ");
- }
- /* Stuff what info we can into control block */
-
- ASSIGN (cb->remote, *remote);
- /* Save local address for connect retries */
- ASSIGN (cb->local, *local);
-
- cb->r_upcall = r_upcall;
- cb->t_upcall = t_upcall;
- cb->s_upcall = s_upcall;
- cb->user = user;
- cb->clone = 0;
-
- switch (mode) {
- case AX_SERVER:
- cb->clone = 1; /*lint !e616 * Note fall-thru */
- case AX_PASSIVE:
- cb->state = NR4STLISTEN;
- return cb;
- case AX_ACTIVE:
- default:
- break;
- }
- /* Format connect request header */
-
- hdr.opcode = NR4OPCONRQ;
- hdr.u.conreq.myindex = uchar(cb->mynum);
- hdr.u.conreq.myid = uchar(cb->myid);
- hdr.u.conreq.window = uchar(Nr4window);
- memcpy (hdr.u.conreq.user, local->user, AXALEN);
-
- /* If I have a unique callsign per interface, then a layer violation */
- /* will be required to determine the "real" callsign for my */
- /* (virtual) node. This suggests that callsign-per-interface is not */
- /* desirable, which answers *that* particular open question. */
-
- memcpy (hdr.u.conreq.node, local->node, AXALEN);
-
- /* Set and start connection retry timer */
-
- cb->cdtries = 1;
- cb->srtt = Nr4irtt;
- set_timer (&cb->tcd, 2 * cb->srtt);
- cb->tcd.func = nr4cdtimeout;
- cb->tcd.arg = cb;
- start_timer (&cb->tcd);
-
- /* Send connect request packet */
-
- nr4sframe (remote->node, &hdr, NULLBUF);
-
- /* Set up initial state and signal state change */
-
- cb->state = NR4STDISC;
- nr4state (cb, NR4STCPEND);
-
- /* Return control block address */
-
- return cb;
- }
-
-
- /* Send a net/rom transport data packet */
- /* Modified to fragment packets larger then Nr_iface->mtu
- * into smaller ones. This allows NETROM to work over ax.25 connections
- * with paclen < 256, WITHOUT fragmenting in the ax.25 layer (ie. v2.1)
- * Thus staying compatible with Thenet, BPQ etc... - WG7J
- */
- int
- send_nr4 (struct nr4cb *cb, struct mbuf *bp)
- {
- struct mbuf *bp1;
- int16 offset, len, size;
-
- if (cb == NULLNR4CB || bp == NULLBUF) {
- free_p (bp);
- return -1;
- }
- if ((len = len_p (bp)) > Nr_iface->mtu) {
- offset = 0;
- /* It is important that all the pushdowns be done before
- * any part of the original packet is freed.
- * Otherwise the pushdown might erroneously overwrite
- * a part of the packet that had been duped and freed.
- */
- while (len != 0) {
- size = min (len, Nr_iface->mtu);
- (void) dup_p (&bp1, bp, offset, size);
- len -= size;
- offset += size;
- enqueue (&cb->txq, bp1);
- }
- free_p (bp);
- } else
- enqueue (&cb->txq, bp);
-
- return nr4output (cb);
- }
-
-
- /* Receive incoming net/rom transport data */
- struct mbuf *
- recv_nr4 (struct nr4cb *cb, int16 cnt)
- {
- struct mbuf *bp;
-
- if (cb->rxq == NULLBUF)
- return NULLBUF;
-
- if (cnt == 0) {
- bp = cb->rxq; /* Just give `em everything */
- cb->rxq = NULLBUF;
- } else {
- bp = ambufw (cnt);
- bp->cnt = pullup (&cb->rxq, bp->data, cnt);
- }
- /* If this has un-choked us, reopen the window */
- if (cb->qfull && len_p (cb->rxq) < Nr4qlimit) {
- cb->qfull = 0; /* Choke flag off */
- nr4ackit (cb); /* Get things rolling again */
- }
- return bp;
- }
-
-
- /* Close a NET/ROM connection */
- void
- disc_nr4 (struct nr4cb *cb)
- {
- struct nr4hdr hdr;
-
- if (cb->state == NR4STLISTEN) {
- free_n4circ (cb);
- return;
- }
- if (cb->state != NR4STCON)
- return;
-
- /* Format disconnect request packet */
-
- hdr.opcode = NR4OPDISRQ;
- hdr.yourindex = uchar(cb->yournum);
- hdr.yourid = uchar(cb->yourid);
-
- /* Set and start timer */
-
- cb->cdtries = 1;
- set_timer (&cb->tcd, 2 * cb->srtt);
- cb->tcd.func = nr4cdtimeout;
- cb->tcd.arg = cb;
- start_timer (&cb->tcd);
-
- /* Send packet */
-
- nr4sframe (cb->remote.node, &hdr, NULLBUF);
-
- /* Signal state change. nr4state will take care of stopping */
- /* the appropriate timers and resetting window pointers. */
-
- nr4state (cb, NR4STDPEND);
-
- }
-
-
- /* Abruptly terminate a NET/ROM transport connection */
- void
- reset_nr4 (struct nr4cb *cb)
- {
- /* Be nice and send a disconnect frame */
- disc_nr4 (cb);
- cb->dreason = NR4RRESET;
- nr4state (cb, NR4STDISC);
- }
-
-
- /* Force retransmission on a NET/ROM transport connection */
- int
- kick_nr4 (struct nr4cb *cb)
- {
- unsigned seq;
- struct timer *t;
-
- if (!nr4valcb (cb))
- return -1;
-
- switch (cb->state) {
- case NR4STCPEND:
- case NR4STDPEND:
- stop_timer (&cb->tcd);
- nr4cdtimeout (cb);
- break;
-
- case NR4STCON:
- if (cb->nextosend != cb->ackxpected) { /* if send window is open: */
- for (seq = cb->ackxpected;
- nr4between ((unsigned) cb->ackxpected, seq, (unsigned) cb->nextosend);
- seq = (seq + 1) & NR4SEQMASK) {
- t = &cb->txbufs[seq % cb->window].tretry;
- stop_timer (t);
- t->state = TIMER_EXPIRE; /* fool retry routine */
- }
- nr4txtimeout (cb);
- }
- break;
- default:
- break;
- }
- return 0;
- }
-
- #endif /* NETROM */
-